<!-- Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -->
<!DOCTYPE html>
<title>Unit Test of e2e.scheme.Ecdh</title>
<script src="../../../../../javascript/closure/base.js"></script>
<script src="test_js_deps-runfiles.js"></script>
<script>
  goog.require('e2e.asymmetric.keygenerator');
  goog.require('e2e.scheme.Ecdh');
  goog.require('e2e.random');
  goog.require('goog.testing.AsyncTestCase');
  goog.require('goog.testing.jsunit');
</script>
<script>
var asyncTestCase = goog.testing.AsyncTestCase.createAndInstall(document.title);


/**
 * Tests that ECDH is self-consistent.
 */
function testConsistency() {
  var ecdhCipher = e2e.asymmetric.keygenerator.newEcdhWithP256();
  // Fake a key fingerprint, since it isn't meaningful at this layer (e.g. no email address).
  ecdhCipher.key.fingerprint = e2e.random.getRandomBytes(20);
  var ecdh = new e2e.scheme.Ecdh(ecdhCipher);
  var m = e2e.random.getRandomBytes(16);
  asyncTestCase.waitForAsync('Waiting for encryption.');
  return ecdh.encryptJavaScript(m).then(function(c) {
    asyncTestCase.waitForAsync('Waiting for decryption.');
    return ecdh.decryptJavaScript(c);
  }).then(function(p){
    assertArrayEquals(m, p);
    asyncTestCase.continueTesting();
  }, fail);
}

/**
 * Tests that ECDH is self-consistent with web crypto.
 */
function testConsistencyWebCrypto() {
  asyncTestCase.waitForAsync('Waiting for key generation');
  e2e.asymmetric.keygenerator.newWebCryptoP256Keys().then(function(ciphers) {
    var ecdsaSigner = ciphers[0];
    var ecdhCipher = ciphers[1];
    // Fake a key fingerprint, since it isn't meaningful at this layer (e.g. no email address).
    ecdhCipher.key.fingerprint = e2e.random.getRandomBytes(20);
    var ecdh = new e2e.scheme.Ecdh(ecdhCipher);
    var m = e2e.random.getRandomBytes(16);
      asyncTestCase.waitForAsync('Waiting for encryption.');
    return ecdh.encryptWebCrypto(m).then(function(c) {
      asyncTestCase.waitForAsync('Waiting for decryption.');
      return ecdh.decryptWebCrypto(c);
    }).then(function(p){
      assertArrayEquals(m, p);
      asyncTestCase.continueTesting();
    });
  }, fail);
}

/**
 * Tests that ECDH is consistent from JS to web crypto.
 */
function testConsistencyJsToWebCrypto() {
  asyncTestCase.waitForAsync('Waiting for key generation');
  e2e.asymmetric.keygenerator.newWebCryptoP256Keys().then(function(ciphers) {
    var ecdsaSigner = ciphers[0];
    var ecdhCipher = ciphers[1];
    // Fake a key fingerprint, since it isn't meaningful at this layer (e.g. no email address).
    ecdhCipher.key.fingerprint = e2e.random.getRandomBytes(20);
    var ecdh = new e2e.scheme.Ecdh(ecdhCipher);
    var m = e2e.random.getRandomBytes(16);
      asyncTestCase.waitForAsync('Waiting for encryption.');
    return ecdh.encryptJavaScript(m).then(function(c) {
      asyncTestCase.waitForAsync('Waiting for decryption.');
      return ecdh.decryptWebCrypto(c);
    }).then(function(p){
      assertArrayEquals(m, p);
      asyncTestCase.continueTesting();
    });
  }, fail);
}

/**
 * Tests that ECDH is consistent from web crypto to JS.
 */
function testConsistencyWebCryptoToJs() {
  var ecdhCipher = e2e.asymmetric.keygenerator.newEcdhWithP256();
  // Fake a key fingerprint, since it isn't meaningful at this layer (e.g. no email address).
  ecdhCipher.key.fingerprint = e2e.random.getRandomBytes(20);
  var jwkKey = e2e.asymmetric.keygenerator.ecToJwk(ecdhCipher.key.pubKey);
  goog.global.crypto.subtle.importKey('jwk', jwkKey, {'name': 'ECDH', 'namedCurve': 'P-256'},
                                 true /* extractable */, [] /* usages */).then(function(webKey) {
    ecdhCipher.setWebCryptoKey({publicKey: webKey});
    var ecdh = new e2e.scheme.Ecdh(ecdhCipher);
    var m = e2e.random.getRandomBytes(16);
    asyncTestCase.waitForAsync('Waiting for encryption.');
    return ecdh.encryptWebCrypto(m).then(function(c) {
      asyncTestCase.waitForAsync('Waiting for decryption.');
      return ecdh.decryptJavaScript(c);
    }).then(function(p){
      assertArrayEquals(m, p);
      asyncTestCase.continueTesting();
    });
  }, fail);
}

/**
 * Tests that ECDH encryption on JS keys works with WebCrypto.
 */
function testJsEncryptWithWebCryptoEcdh() {
  asyncTestCase.waitForAsync('Waiting for key generation');
  var ecdhCipher = e2e.asymmetric.keygenerator.newEcdhWithP256();
  // Fake a key fingerprint, since it isn't meaningful at this layer (e.g. no email address).
  ecdhCipher.key.fingerprint = e2e.random.getRandomBytes(20);
  var ecdh = new e2e.scheme.Ecdh(ecdhCipher);
  var m = e2e.random.getRandomBytes(16);
  asyncTestCase.waitForAsync('Waiting for encryption.');
  ecdh.encryptJavaScriptKeyWithWebCrypto(m).then(function(c) {
    asyncTestCase.waitForAsync('Waiting for decryption.');
    return ecdh.decryptJavaScript(c);
  }).then(function(p){
    assertArrayEquals(m, p);
    asyncTestCase.continueTesting();
  }, fail);
}

/**
 * Tests that ECDH decryption on JS keys works with WebCrypto.
 */
function testJsDecryptWithWebCryptoEcdh() {
  asyncTestCase.waitForAsync('Waiting for key generation');
  var ecdhCipher = e2e.asymmetric.keygenerator.newEcdhWithP256();
  // Fake a key fingerprint, since it isn't meaningful at this layer (e.g. no email address).
  ecdhCipher.key.fingerprint = e2e.random.getRandomBytes(20);
  var ecdh = new e2e.scheme.Ecdh(ecdhCipher);
  var m = e2e.random.getRandomBytes(16);
  asyncTestCase.waitForAsync('Waiting for encryption.');
  ecdh.encryptJavaScript(m).then(function(c) {
    asyncTestCase.waitForAsync('Waiting for decryption.');
    return ecdh.decryptJavaScriptKeyWithWebCrypto(c);
  }).then(function(p){
    assertArrayEquals(m, p);
    asyncTestCase.continueTesting();
  }, fail);
}

</script>
